서버와 클라이언트 배포를 위한 AWS EC2 설정

✒️ 2025-05-26 14:24 내용 수정


참고 자료 : Geeksforgeeks What is Elastic Compute Could(EC2), AWS EC2 Node.js 서버 배포, Iheunoia's AWS 웹 어플리케이션 배포하기(EC2), 오호's AWS EC2 프론트 배포 이렇게만 해보자, hakawati's AWS에 EC2 생성하기


1. EC2 가입 및 인스턴스 생성


2. EC2와 RDS 연결


3. AWS EC2 인스턴스에서 ubuntu 설정

  1. 인스턴스에 연결을 성공했다면 배포 설정을 진행하기 전에 파일 편집용 vim을 설치한다.
# 시스템 패키지 목록을 업데이트하고, 필요한 패키지를 업그레이드
sudo apt update -y

# vim 설치
sudo apt-get install vim
  1. EC2와 RDS를 연결했다면 인스턴스에 사용하려는 DB 서버 CLI를 설치한다. 설치가 완료 되었다면 DB에 접속하여 잘 연결되는지 확인한다.
    • 프로젝트에선 MySQL을 사용해서 mysql-server를 설치했다.
# mysql 설치
sudo apt install mysql-server

# 접속
mysql -u 계정이름 -p -h host주소(RDS엔드포인트)
  1. ubuntu 홈 경로 /home/ubuntu 에서 배포할 서버의 root 폴더로 이동한다.
    • 만약 폴더를 새로 만들어서 작업하고 싶다면 mkdir 폴더명으로 새 폴더를 생성한다.
cd server
  1. nodejs, npm을 설치한다.
# 패키지 업데이트 확인
sudo apt update

# nodejs npm 설치
sudo apt-get install nodejs npm
  1. 설치된 node와 npm의 버전도 확인해본다.
    • 설치가 안되어 있다면 버전 확인이 안된다.
# node 버전 확인
node -v

# npm 버전 확인
npm -v
  1. 의존성 패키지를 설치한다.
    • node_modules 폴더가 생성되고 파일들을 다운 받는다.
      • Node 수업에서 패키지 관련 설명을 제대로 들었으면 node_modules를 로컬에서 인스턴스로 파일전송하는 뻘짓을 하지 않았을 것이다
npm install
  1. github에 올려둔 서버와 클라이언트 파일을 받기 위해 git clone git주소를 실행한다.
git clone https://github.com/이름/리포지토리

server production git.png

# local VSC terminal
scp -i ssh키파일 전송할파일 ubuntu@host:/파일저장경로
  1. 이제 server와 client의 host 설정을 변경한다. .env 파일에 HOST를 환경 변수로 저장했다면 HOST를 HOST=0.0.0.0으로 변경한다.
    • 이렇게 적용한 후에 서버나 클라이언트를 실행하고, 로컬 브라우저에서 EC2의 동적 ip(17.114.69.1 같은 것)와 개방 허용된 포트를 입력하면 접근할 수 있다.
# client .env, server .env 둘 다 있다면 모두 적용
HOST=0.0.0.0

# EC2에서 개방 설정한 PORT로 변경
PORT=5000
// server.js
require("dotenv").config();

const PORT = process.env.PORT || 5000;
const HOSTNAME = process.env.HOSTNAME || 'localhost';

server.listen(PORT, HOSTNAME, () => {
	console.log(`server on : http://${HOSTNAME}:${PORT}/`);
});

server production test.png


4. 메모리 부족 현상 해결

# 메모리 사용량 확인
free

# 읽기 쉬운 형태로 출력
free -h
# 메모리 사용량 모니터링
# -r : 메모리 사용량 보고
# 1초 간격
sar -r 1
# 실시간 프로세스 및 자원 상태 모니터링
top
sudo apt install sysstat
mpstat
sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
// client package.json
"scripts": {
	"start": "react-scripts --max_old_space_size=4096 start",
	"build": "react-scripts GENERATE_SOURCEMAP=false --max_old_space_size=4096 build",
	"test": "react-scripts test",
	"eject": "react-scripts eject"
},
# heap 메모리 부족 현상 해결을 위한 client .env 설정
GENERATE_SOURCEMAP=false
NODE_OPTIONS="--max-old-space-size=4096"
sudo swapoff -v /mnt/swapfile
sudo rm /mnt/swapfile

5. Nginx 설치 및 설정

Mixed Content: The page at '[https://test.vercel.app/api](https://test.vercel.app/api)' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint '[http://server_domain/api/](http://server_domain/api/)'. This request has been blocked; the content must be served over HTTPS.
# 패키지 업데이트
sudo apt update
# Nginx 설치
sudo apt install nginx
# 방화벽에서 Nginx의 기본 포트인 80(HTTP)와 443(HTTPS) 허용
sudo ufw allow "Nginx Full"
# https 인증서를 위한 certbot 설치
sudo snap install --classic certbot
# nginx 설정
sudo certbot --nginx
##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

# http 포트(80)으로 들어오는 요청을 수신
# 모든 http 요청을 301 코드(moved permanently)와 함께 연결할 주소로 리디렉션(http->https)
server {
	listen 80;
	listen [::]:80;
	# 서버 도메인 설정
	server_name 서버도메인;

	return 301 연결할주소;
}

# https 포트(443)으로 들어오는 요청을 수신
server {
	listen 443 ssl; # managed by Certbot
	listen [::]:443 ssl;
	# 서버 도메인 설정
	server_name 서버도메인;

	# SSL 인증서 경로
	ssl_certificate "인증서주소"; # managed by Certbot
	ssl_certificate_key "인증서주소"; # managed by Certbot
	
	# 기타 SSL 설정
	include "/etc/letsencrypt/options-ssl-nginx.conf"; # managed by Certbot
	ssl_dhparam "/etc/letsencrypt/ssl-dhparams.pem"; # managed by Certbot

	# 서버 도메인의 루트 경로에 대한 요청을 처리
	location / {
		# 로컬 host의 10000번 포트로 전달함
		proxy_pass http://localhost:10000;
		# 원본 요청의 호스트 헤더를 전달
		proxy_set_header HOST $host;
		# 원본 요청의 클라이언트 ip 주소를 전달
		proxy_set_header X-Real-IP $remote_addr;
		# 원본 요청의 X-Forwarded-For 헤더를 전달
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		# 원본 요청ㅇ의 프로토콜을 https로 설정
		proxy_set_header X-Forwarded-Proto https;
		# proxy 응답의 리디렉션을 비활성화
		proxy_redirect off;
	}
}
# nginx 재시작
sudo systemctl restart nginx
# client/.env
# 서버 주소
REACT_APP_SERVER_IP = 구매한 서버 도메인
// src/lib/axios.js
// 이제 클라이언트에서 axios를 요청할 때 서버 도메인으로 가게끔 설정한다.
import axios from 'axios';
axios.defaults.withCredentials = true; // 쿠키 공유 허용

const server = process.env.REACT_APP_SERVER_IP

const instance = axios.create({
    baseURL : `https://${server}/api/`
});

export default instance;
# server/.env
# 도메인
SERVER_DOMAIN = 서버 도메인
CLIENT_DOMAIN = 클라이언트 도메인
// server.js
const whiteList = [
  `http://${HOSTNAME}:${PORT}`, `https://${HOSTNAME}:${PORT}`,
  `http://0.0.0.0:3000`, `https://0.0.0.0:3000`,
  `https://${SERVER_DOMAIN}`,
  `https://${CLIENT_DOMAIN}`, `http://${CLIENT_DOMAIN}:3000`
]